#include "Game.h"

IGame* createGame( HINSTANCE hInst, HWND hWnd )
{
	return new Game( hInst, hWnd );
}

Game::Game( HINSTANCE hInst, HWND hWnd ) :
	m_input( hInst, hWnd )
{
	// initialize camera
	m_camera.hand = Camera::RIGHTHANDED;

	m_camera.eye = float3( 0, 0, 15.f );
	m_camera.at  = float3( 0, 0, 0 );
	m_camera.up  = float3( 0, 1, 0 );

	m_camera.projectionType = Camera::PERSPECTIVE_FOV;
	m_camera.perspectiveFov.fovy = D3DXToRadian(45.f);
	m_camera.perspectiveFov.aspect = 1024.f/768.f;

	m_camera.zn = 1.0f;
	m_camera.zf = 100.0f;

	// initialize ground
	m_ground.rigidBody.invLocalInertia = zero33();
	m_ground.rigidBody.invMass = 0;
}

Game::~Game()
{
	m_d3dDevice = 0;
}

void Game::onCreateGraphics( D3DDevice device )
{
	m_d3dDevice = device;

	m_d3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CW );

	float44 world = identity44();
	float44 view = m_camera.view();
	float44 proj = m_camera.projection();

	m_d3dDevice->SetTransform( D3DTS_WORLD, &world );
	m_d3dDevice->SetTransform( D3DTS_VIEW, &view );
	m_d3dDevice->SetTransform( D3DTS_PROJECTION, &proj );

	//
	poly::Polygon polygon;
	polygon.push_back( float3( +1.0f, -0.5f, 0 ) );
	polygon.push_back( float3( +0.5f, +0.5f, 0 ) );
	polygon.push_back( float3( -0.5f, +0.5f, 0 ) );
	polygon.push_back( float3( -1.0f, -0.5f, 0 ) );

	m_body.setup( m_d3dDevice, polygon, float4( 0.f, 0.3f, 0.3f, 0.3f ) );
	m_body.rigidBody.invMass = 0.3f;
	m_body.rigidBody.pos = float3(0, 4.f, 0);

	poly::Polygon leftLegPoly;
	leftLegPoly.push_back( float3( -0.5f, +0.1f, 0 ) );
	leftLegPoly.push_back( float3( -0.5f, -0.1f, 0 ) );
	leftLegPoly.push_back( float3( +0.5f, +0.0f, 0 ) );

	m_leftLeg.setup( m_d3dDevice, leftLegPoly, float4( 0.f, 1.f, 0.5f, 0.2f ) );
	m_leftLeg.rigidBody.pos = float3(-0.5f, 3.f, 0);
	m_leftLeg.rigidBody.friction = 20.f;
	m_leftLeg.rigidBody.elasticity = 0.1f;

	poly::Polygon rightLegPoly;
	rightLegPoly.push_back( float3( +0.5f, +0.1f, 0 ) );
	rightLegPoly.push_back( float3( -0.5f, +0.0f, 0 ) );
	rightLegPoly.push_back( float3( +0.5f, -0.1f, 0 ) );

	m_rightLeg.setup( m_d3dDevice, rightLegPoly, float4( 0.f, 1.f, 0.5f, 0.2f ) );
	m_rightLeg.rigidBody.pos = float3(+0.5f, 3.f, 0);
	m_rightLeg.rigidBody.friction = 20.f;
	m_rightLeg.rigidBody.elasticity = 0.1f;

	poly::Polygon groundPoly;
	groundPoly.push_back( float3( +5.f, 0.f, 0 ) );
	groundPoly.push_back( float3( -5.f, 0.f, 0 ) );
	groundPoly.push_back( float3( 0.f, -5.f, 0 ) );

	m_ground.setup( m_d3dDevice, groundPoly, float4( 0.f, 0.6f, 0.1f, 0.1f ) );
	m_ground.rigidBody.invLocalInertia = zero33();
	m_ground.rigidBody.invMass = 0.f;
	m_ground.rigidBody.friction = 1.f;

	m_spiral[0].rigidBody1 = &m_body.rigidBody;
	m_spiral[0].rigidBody2 = &m_leftLeg.rigidBody;
	m_spiral[0].pointOfApp1 = float3( -1.0f, -0.5f, 0 );
	m_spiral[0].pointOfApp2 = float3( -0.5f, +0.1f, 0 );
	m_spiral[0].torqueDensity = 1;
	m_spiral[0].deviation = +0.3f;
	
	m_spiral[1].rigidBody1 = &m_body.rigidBody;
	m_spiral[1].rigidBody2 = &m_rightLeg.rigidBody;
	m_spiral[1].pointOfApp1 = float3( +1.0f, -0.5f, 0 );
	m_spiral[1].pointOfApp2 = float3( +0.5f, +0.1f, 0 );
	m_spiral[1].torqueDensity = 1;
	m_spiral[1].deviation = -0.3f;

	m_collision.colliders.insert( &m_body );
	m_collision.colliders.insert( &m_leftLeg );
	m_collision.colliders.insert( &m_rightLeg );
	m_collision.colliders.insert( &m_ground );

	m_dynamics.constraints.insert( &m_collision );
	m_dynamics.constraints.insert( &m_spiral[0] );
	m_dynamics.constraints.insert( &m_spiral[1] );

	m_dynamics.dynObjects.insert( &m_body );
	m_dynamics.dynObjects.insert( &m_leftLeg );
	m_dynamics.dynObjects.insert( &m_rightLeg );
	m_dynamics.dynObjects.insert( &m_ground );
}

void Game::onResetGraphics( D3DDevice device )
{
	m_d3dDevice = device;

	m_d3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CW );

	float44 view = m_camera.view();
	float44 proj = m_camera.projection();

	m_d3dDevice->SetTransform( D3DTS_VIEW, &view );
	m_d3dDevice->SetTransform( D3DTS_PROJECTION, &proj );
}

void Game::onLostGraphics()
{
}

void Game::onFrameMove(float dt)
{
	m_dynamics.step( dt );
	m_body.rigidBody.addForce(float3(0,-1.f,0));
	m_leftLeg.rigidBody.addForce(float3(0,-1.f,0));
	m_rightLeg.rigidBody.addForce(float3(0,-1.f,0));

	if( GetAsyncKeyState( VK_LEFT ) & 0x8000 )
	{
		m_body.rigidBody.addRotationalImpulse( float3(0,0,+0.1f) );
		m_leftLeg.rigidBody.addRotationalImpulse( float3(0,0,-0.1f) );
	}
	if( GetAsyncKeyState( VK_RIGHT ) & 0x8000 )
	{
		m_body.rigidBody.addRotationalImpulse( float3(0,0,-0.1f) );
		m_rightLeg.rigidBody.addRotationalImpulse( float3(0,0,+0.1f) );
	}
}

void Game::onFrameRender(float dt)
{
	float44 world = identity44();
	m_dynamics.render( dt );
}

void Game::onDestroyGraphics()
{
}
